﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    public class TokenHelper
    {
        private static TokenHelper tokenhelper = new TokenHelper();
        private Random random = new Random((int)DateTime.Now.Ticks);

        string[] RandomKey = null;

        private TokenHelper()
        {
            string items = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0";
            RandomKey = items.Split(' ');


        }

        public static TokenHelper GetInstance()
        {
            return tokenhelper;
        }

        /// <summary>
        /// 获取随机的Token
        /// </summary>
        /// <param name="count">Token的长度</param>
        /// <returns></returns>
        public string GetRandomToken(int count = 64)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < count; i++)
            {
                sb.Append(RandomKey[random.Next(RandomKey.Length)]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 获得加密的data作为Token
        /// </summary>
        /// <param name="data"></param>
        /// <param name="password"></param>
        /// <param name="salt"></param>
        /// <returns></returns>
        public string EncryptionToken(string data, string password, byte[] salt)
        {
            byte[] ciphertext;
            var key = new Rfc2898DeriveBytes(password, salt);
            var algorithm = new RijndaelManaged();
            algorithm.Key = key.GetBytes(16);
            algorithm.IV = key.GetBytes(16);

            var sourceBytes = new UnicodeEncoding().GetBytes(data);

            using (var sourceStream = new MemoryStream(sourceBytes))
            using (var destinationStream = new MemoryStream())
            using (var crypto = new CryptoStream(sourceStream, algorithm.CreateEncryptor(), CryptoStreamMode.Read))
            {
                MoveBytes(crypto, destinationStream);
                ciphertext = destinationStream.ToArray();
            }
            return new UnicodeEncoding().GetString(ciphertext);
        }

        /// <summary>
        /// 获取Token解密后的结果
        /// </summary>
        /// <param name="token"></param>
        /// <param name="password"></param>
        /// <param name="salt"></param>
        /// <returns></returns>
        public string DecryptionToken(string token, string password, byte[] salt)
        {
            string data = string.Empty;
            var key = new Rfc2898DeriveBytes(password, salt);
            // Try to decrypt, thus showing it can be round-tripped.
            var algorithm = new RijndaelManaged();
            algorithm.Key = key.GetBytes(16);
            algorithm.IV = key.GetBytes(16);
            using (var sourceStream = new MemoryStream(new UnicodeEncoding().GetBytes(token)))
            using (var destinationStream = new MemoryStream())
            using (var crypto = new CryptoStream(sourceStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read))
            {
                MoveBytes(crypto, destinationStream);
                var decryptedBytes = destinationStream.ToArray();
                data = new UnicodeEncoding().GetString(decryptedBytes);
            }

            return data;
        }

        private void MoveBytes(Stream source, Stream dest)
        {
            byte[] bytes = new byte[2048];
            var count = source.Read(bytes, 0, bytes.Length);
            while (0 != count)
            {
                dest.Write(bytes, 0, count);
                count = source.Read(bytes, 0, bytes.Length);
            }
        }
    }
}
